/** for ActionEvent */
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.event.ActionEvent;

/** for ActionListener */
import java.awt.event.ActionListener;

/** for File */
import java.io.File;

/** for FileInputStream */
import java.io.FileInputStream;

/** for IOException */
import java.io.IOException;

/** for InvalidClassException */
import java.io.InvalidClassException;

/** for ObjectInputStream */
import java.io.ObjectInputStream;

/** for Map */
import java.util.Map;

import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
/** for FileFilter */
import javax.swing.filechooser.FileFilter;

/** 
 * This is a class to handel GUI for Player
 * @author Code Traders
 * @version 1.0
 */
public class SpaceTraderGUI implements ChangeListener, ActionListener, View {
	
	/**
	 * JFrame for the SpaceTraderGUI
	 */
	private JFrame frame;
	
	/**
	 * main text field
	 */
	private JTextField textField;
	
	/**
	 * JSpinners for the skill points
	 */
	private JSpinner spinner_1, spinner_2, spinner_3, spinner_4;
	
	/**
	 * ok button
	 */
	private JButton btnOk;
	
	/**
	 * JLabels showing the remaining points and the title
	 */
	private JLabel remPoint, lblPointsRemaining;
	
	/**
	 * SpaceTraderMainGUI main window
	 */
	private SpaceTraderMainGUI mainWindow;
	
	/**
	 * Combo box for the difficulties
	 */
	private JComboBox<String> comboBox;
	
	/**
	 * Width and height of the window
	 */
	private static final int WIDTH = 270, HEIGHT = 340;
	
	/**
	 * Launch the application.
	 * @param args 
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					final SpaceTraderGUI window = new SpaceTraderGUI();
					window.frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}
	
	/**
	 * Not used
	 * To get SpaceTraderMainGUI
	 * @return MainWindow
	 */
	@Override
	public SpaceTraderMainGUI getMainWindow() {
		return mainWindow;
	}
	
	/**
	 * Not used
	 * To set SpaceTraderMainGUI
	 * @param mainWindow
	 */
	@Override
	public void setMainWindow(SpaceTraderMainGUI mainWindow) {
		this.mainWindow = mainWindow;
	}

	/**
	 * Create the application.
	 */
	public SpaceTraderGUI() {
		initialize();
	}

	/**
	 * Initialize the contents of the frame.
	 */
	private void initialize() {
		frame = new JFrame();
		frame.setBounds(Numbers.HUNDRED.getNumber(), 
				Numbers.HUNDRED.getNumber(), WIDTH, HEIGHT);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.getContentPane().setLayout(null);
		
		final JLabel lblPlayerName = new JLabel("Player Name:");
		lblPlayerName.setBounds(Numbers.TWENTY_THREE.getNumber(), 
				Numbers.SIXTY_TWO.getNumber(), 
				Numbers.EIGHTY_ONE.getNumber(), Numbers.SIXTEEN.getNumber());
		frame.getContentPane().add(lblPlayerName);
		
		final JLabel lblConfiguration = new JLabel("Configuration");
		lblConfiguration.setFont(new Font("Lucida Grande", Font.BOLD, 
				Numbers.TWENTY.getNumber()));
		lblConfiguration.setBounds(Numbers.SIXTY.getNumber(), 
				Numbers.SIX.getNumber(), 
				Numbers.HUNDRED_FORTY_THREE.getNumber(), 
				Numbers.FORTY_FOUR.getNumber());
		frame.getContentPane().add(lblConfiguration);
		
		final JLabel lblDifficulty = new JLabel("Difficulty:");
		lblDifficulty.setBounds(Numbers.TWENTY_THREE.getNumber(), 
				Numbers.NINTY_FOUR.getNumber(), 
				Numbers.SIXTY_EIGHT.getNumber(), 
				Numbers.SIXTEEN.getNumber());
		frame.getContentPane().add(lblDifficulty);
		
		final JLabel lblSkillPoints = new JLabel("Skill Points:");
		lblSkillPoints.setBounds(Numbers.TWENTY_THREE.getNumber(), 
				Numbers.HUNDRED_TWENTY_FIVE.getNumber(), 
				Numbers.EIGHTY_ONE.getNumber(), 
				Numbers.SIXTEEN.getNumber());
		frame.getContentPane().add(lblSkillPoints);
		
		remPoint = new JLabel("16");
		remPoint.setBounds(Numbers.HUNDRED.getNumber() 
				+ Numbers.SIXTEEN.getNumber(), 
				Numbers.HUNDRED_TWENTY_FIVE.getNumber(), 
				Numbers.SIXTEEN.getNumber(), 
				Numbers.SIXTEEN.getNumber());
		frame.getContentPane().add(remPoint);
		
		lblPointsRemaining = new JLabel("points remaining");
		lblPointsRemaining.setBounds(Numbers.HUNDRED_FORTY.getNumber(), 
				Numbers.HUNDRED_TWENTY_FIVE.getNumber(), 
				Numbers.HUNDRED_SEVEN.getNumber(), 
				Numbers.SIXTEEN.getNumber());
		frame.getContentPane().add(lblPointsRemaining);
		
		final JLabel lblPilot = new JLabel("Pilot:");
		lblPilot.setBounds(Numbers.FIFTY_THREE.getNumber(), 
				Numbers.HUNDRED_SIXTY_SIX.getNumber(), 
				Numbers.SIXTY_ONE.getNumber(), 
				Numbers.SIXTEEN.getNumber());
		frame.getContentPane().add(lblPilot);
		
		final JLabel lblFighter = new JLabel("Fighter:");
		lblFighter.setBounds(Numbers.FIFTY_THREE.getNumber(), 
				Numbers.HUNDRED_NINTY_FOUR.getNumber(), 
				Numbers.SIXTY_ONE.getNumber(), 
				Numbers.SIXTEEN.getNumber());
		frame.getContentPane().add(lblFighter);
		
		final JLabel lblTrader = new JLabel("Trader:");
		lblTrader.setBounds(Numbers.FIFTY_THREE.getNumber(), 
				Numbers.TWO_HUNDRED_TWENTY_TWO.getNumber(), 
				Numbers.SIXTY_ONE.getNumber(), 
				Numbers.SIXTEEN.getNumber());
		frame.getContentPane().add(lblTrader);
		
		final JLabel lblEngineer = new JLabel("Engineer:");
		lblEngineer.setBounds(Numbers.FIFTY_THREE.getNumber(), 
				Numbers.TWO_HUNDRED_FIFTY.getNumber(), 
				Numbers.SIXTY.getNumber() + 1, 
				Numbers.SIXTEEN.getNumber());
		frame.getContentPane().add(lblEngineer);
		
		textField = new JTextField();
		textField.setBounds(Numbers.HUNDRED_SIXTEEN.getNumber(), 
				Numbers.FIFTY_SIX.getNumber(), 
				Numbers.HUNDRED_THIRTY_FOUR.getNumber(), 
				Numbers.TWENTY_EIGHT.getNumber());
		frame.getContentPane().add(textField);
		textField.setColumns(Numbers.TEN.getNumber());
		
		comboBox = new JComboBox<String>();
		comboBox.setModel(new DefaultComboBoxModel<String>
		(new String[] {"Beginner", "Easy", "Normal", "Hard", "Impossible"}));
		comboBox.setBounds(Numbers.HUNDRED_SIXTEEN.getNumber(), 
				Numbers.NINTY.getNumber(), 
				Numbers.HUNDRED_THIRTY_FOUR.getNumber(), 
				Numbers.TWENTY_SEVEN.getNumber());
		comboBox.setSelectedIndex(Numbers.TWO.getNumber());
		frame.getContentPane().add(comboBox);
		
		spinner_1 = new JSpinner();
		spinner_1.setModel(new SpinnerNumberModel(0, 0, Numbers.SIXTEEN.getNumber(), 1));
		spinner_1.setBounds(Numbers.HUNDRED_TWENTY_EIGHT.getNumber(), 
				Numbers.HUNDRED_SIXTY.getNumber(), 
				Numbers.FIFTY_ONE.getNumber(), 
				Numbers.TWENTY_EIGHT.getNumber());
		frame.getContentPane().add(spinner_1);
		spinner_1.addChangeListener(this);
		
		spinner_2 = new JSpinner();
		spinner_2.setModel(new SpinnerNumberModel(0, 0, Numbers.SIXTEEN.getNumber(), 1));
		spinner_2.setBounds(Numbers.HUNDRED_TWENTY_EIGHT.getNumber(), 
				Numbers.HUNDRED_EIGHTY_EIGHT.getNumber(), 
				Numbers.FIFTY_ONE.getNumber(), 
				Numbers.TWENTY_EIGHT.getNumber());
		frame.getContentPane().add(spinner_2);
		spinner_2.addChangeListener(this);
		
		spinner_3 = new JSpinner();
		spinner_3.setModel(new SpinnerNumberModel(0, 0, Numbers.SIXTEEN.getNumber(), 1));
		spinner_3.setBounds(Numbers.HUNDRED_TWENTY_EIGHT.getNumber(), 
				Numbers.TWO_HUNDRED_SIXTEEN.getNumber(), 
				Numbers.FIFTY_ONE.getNumber(), 
				Numbers.TWENTY_EIGHT.getNumber());
		frame.getContentPane().add(spinner_3);
		spinner_3.addChangeListener(this);
		
		spinner_4 = new JSpinner();
		spinner_4.setModel(new SpinnerNumberModel(0, 0, Numbers.SIXTEEN.getNumber(), 1));
		spinner_4.setBounds(Numbers.HUNDRED_TWENTY_EIGHT.getNumber(), 
				Numbers.TWO_HUNDRED_FORTY_FOUR.getNumber(), 
				Numbers.FIFTY_ONE.getNumber(), 
				Numbers.TWENTY_EIGHT.getNumber());
		frame.getContentPane().add(spinner_4);
		spinner_4.addChangeListener(this);
		
		btnOk = new JButton("OK");
		btnOk.setBounds(Numbers.HUNDRED_NINTY_FOUR.getNumber(), 
				Numbers.TWO_HUNDRED_SEVENTY_TWO.getNumber(), 
				Numbers.FIFTY_ONE.getNumber(), 
				Numbers.TWENTY_NINE.getNumber());
		frame.getContentPane().add(btnOk);
		btnOk.addActionListener(this);
		
		final JButton loadButton = new JButton("Load");
		loadButton.setBounds(Numbers.SIX.getNumber(), 
				Numbers.TWO_HUNDRED_EIGHTY_THREE.getNumber(), 
				Numbers.SIXTY_ONE.getNumber(), 
				Numbers.TWENTY_NINE.getNumber());
		frame.getContentPane().add(loadButton);
		loadButton.addActionListener(new ButtonListener());
		
	}

	/**
	 * ChangeListener method for the JSpinner
	 * 
	 * @param e ChangeEvent
	 */
	@Override
	public void stateChanged(ChangeEvent e) {
		final JSpinner spinner = (JSpinner) e.getSource();
		final int num = Numbers.SIXTEEN.getNumber() - (((int) spinner_1.getValue()) +
				((int) spinner_2.getValue()) + ((int) spinner_3.getValue())
				+ ((int) spinner_4.getValue()));
		if (num < 0) {
			spinner.setValue(((int) spinner.getValue()) - 1);
		} else {
			remPoint.setText("" + num);
			if (num <= 1) {
				lblPointsRemaining.setText("point remaining");
			} else {
				lblPointsRemaining.setText("points remaining");
			}
		}
	}

	/**
	 * ActionListener method for the buttons
	 * 
	 * @param e ActionEvent
	 */
	@Override
	public void actionPerformed(ActionEvent e) {
		if (e.getActionCommand().equals("OK")) {
			if (!(remPoint.getText()).equals("0")) {
				JOptionPane.showMessageDialog(frame,
						"Please use all the points", "Failure",
						JOptionPane.ERROR_MESSAGE);
			} else if (textField.getText().length() == 0  ) {
				JOptionPane.showMessageDialog(frame,
						"Please input valid Name", "Failure", JOptionPane.ERROR_MESSAGE);
			} else if (textField.getText().length() > 0 ) {
//				textField.getText();
//				String[] arg = {textField.getText(), spinner_1.getValue().toString(), spinner_2.getValue().toString(), spinner_3.getValue().toString(), spinner_4.getValue().toString()};
				//SpaceTraderMainGUI.main(arg);
				frame.setVisible(false);
			}
		}
	}

	/**
	 * Getter for the name textfield
	 * 
	 * @return name
	 */
	@Override
	public String getName() {
		//p.setName(textField.getName());
		return textField.getName();
	}

	/**
	 * Getter for the skill points
	 * 
	 * @return Player created with the appropriate points
	 */
	@Override
	public Player getSkills() {
		final Player player = new Player();
		player.setName(textField.getText());
		player.setPilot((int) spinner_1.getValue());
		player.setFighter((int) spinner_2.getValue());
		player.setTrader((int) spinner_3.getValue());
		player.setEngineer((int) spinner_4.getValue());
		
		return player;
	}
	
	/**
	 * This is to get difficulty
	 * @return difficulty
	 */
	@Override
	public int getDifficulty() {
		return comboBox.getSelectedIndex();
	}

	/**
	 * Registers the player to Main_Present
	 * @param al
	 */
	@Override
	public void registerAccept(ActionListener al) {
	    btnOk.addActionListener(al);
	}

	/**
	 * sets visibility of the frame
	 */
	@Override
	public void show() {
		frame.setVisible(true);
	}

	/**
	 * sets enabled
	 * @param flag
	 */
	@Override
	public void enableAccept(boolean flag) {
		btnOk.setEnabled(flag);
	}
	
	/**
	 * This method loads the saved state of the game from a file. 
	 * @throws IOException
	 * @throws ClassNotFoundException
	 * @param file The file path (file name) where
	 *  the user wants the save file to be loaded from
	 * @return ture or false
	 */
	@SuppressWarnings({ "unchecked" })
	public boolean canLoad(File file) throws IOException, ClassNotFoundException {
		final int ind = file.getName().lastIndexOf('.') + 1;
		if (!file.getName().substring(ind).equals("codetraders")) {
			JOptionPane.showMessageDialog(null, "Wrong File Loaded");
			return false;
		}
		final ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
		try {
			Singleton.INSTANCE.setInstance((Map<String, Object>) in.readObject());
		} catch (InvalidClassException e) {
			JOptionPane.showMessageDialog(null, "Wrong File Loaded");
			e.printStackTrace();
			return false;
		} finally {
			in.close();
		}
		return true;
	}
	
	/**
	 * This class is the ButtonListener implementing
	 *  the ActionListener for the save/load buttons.
	 * @author Code Traders
	 */
	private class ButtonListener implements ActionListener {
		
		/**
		 * JFileChoose for the save and the load buttons
		 */
		private final JFileChooser fc;
		
		/**
		 * This is a constructor for the ButtonListener, 
		 * which takes in the file name as a String. 
		 * 
		 * 
		 */
		private ButtonListener() {
			fc = new JFileChooser();
			fc.addChoosableFileFilter(new CodeTradersFileFilter());
		}
		
		/**
		 * This is the main method to be performed when the ActionEvent is called, 
		 * to either save or load depending on the button that was pressed. 
		 * 
		 * @param e The ActionEvent called
		 */
		@Override
		public void actionPerformed(ActionEvent e) {
			final int returnVal = fc.showDialog(null, "Load");
			if ( returnVal == JFileChooser.APPROVE_OPTION ) {
				try {
					boolean loaded = canLoad(fc.getSelectedFile());
					if (!loaded) {
						return;
					}
					frame.setVisible(false);
					mainWindow = new SpaceTraderMainGUI(null, true);
                	mainWindow.show();
				} catch (IOException e1) {
					e1.printStackTrace();
				} catch (ClassNotFoundException e1) {
					e1.printStackTrace();
				}
			}
//			requestFocusInWindow();
		}
		
		/**
		 * this is a tostring method.
		 * @return tostring. 
		 */
		@Override
		public String toString() {
			return super.toString();
		}
	}
	
	/**
	 * This class is a FileFilter to filter 
	 * the allowed file extension type (*.codetraders)
	 * @author Code Traders
	 */
	private static class CodeTradersFileFilter extends FileFilter {
		
		/**
		 * This method sets up the accepted file extension for the FileChooser
		 * 
		 * @param f The file to be checked if is should be accepted
		 * @return true if it is in a .codetraders format, false otherwise
		 */
		@Override
		public boolean accept(File f) {
			if (f.isDirectory()) {
				return true;
			}
			final String name = f.getName();
			final int i = name.lastIndexOf('.');
			
			if ( i > 0 && i < name.length() - 1 ) {
				final String ext = name.substring(i + 1).toLowerCase();
				if ( ext.equals("codetraders") ) {
					return true;
				}
			}
			return false;
		}
		
		/**
		 * This method sets up the description of the format for the FileChooser
		 * 
		 * @return The description of the format (.codetraders)
		 */
		@Override
		public String getDescription() {
			return "Space Trader Save File (*.codetraders)";
		}
		
		/**
		 * this is a tostring method.
		 * @return tostring. 
		 */
		@Override
		public String toString() {
			return super.toString();
		}
	}

	/** 
	 * This is a class to set setvisible as false.
	 * 
	 */
	@Override
	public void hide() {
		// TODO Auto-generated method stub
		frame.setVisible(false);
	}
	
	/**
	 * this is a tostring method.
	 * @return tostring. 
	 */
	@Override
	public String toString() {
		return super.toString();
	}
}
